from sqlalchemy import (
    Column,
    Integer,
    String,
    ForeignKey,
    or_,
    and_,
)

from sqlalchemy.orm import relationship, declarative_base
from pprint import pprint
from en_url import engine

try:
    # 创建声明式的基类，所有的模型类都要继承自这个基类
    Base = declarative_base()

    # 定义User模型类
    class User(Base):
        # 指定数据库的表名为users
        __tablename__ = "users"
        id = Column(Integer, primary_key=True)
        name = Column(String(50))
        fullname = Column(String(50))
        # 定义与Address表一对多的关系，back_populates指定反向引用
        addresses = relationship("Address", back_populates="user")

    class Address(Base):
        # 指定数据库的表名为users
        __tablename__ = "addresses"
        id = Column(Integer, primary_key=True)
        email_address = Column(String(50), nullable=False)
        user_id = Column(Integer, ForeignKey("users.id"))
        user = relationship("User", back_populates="addresses")

    # 在数据库中创建所有的定义的模型对应的表
    Base.metadata.create_all(engine)

except Exception as e:
    print(f"创建数据库表失败:{e}")

# 导入会话创建器
from sqlalchemy.orm import sessionmaker

# 创建会话工厂，绑定上面定义的数据库引擎
Session = sessionmaker(bind=engine)
# 创建会话对象
session = Session()

# 导入joinedload用于实现立即加载
from sqlalchemy.orm import joinedload

"""
避免 N+1 查询问题：如果不加 joinedload，当你遍历用户访问地址时，每个用户都会触发一次额外的数据库查询
一次性加载：用 JOIN 语句一次性把用户和地址数据都查出来
"""
# 查询所有的User对象，并且立即加载其关联的addresses数据列表
users = session.query(User).options(joinedload(User.addresses)).all()
for user in users:
    print(user.fullname)
    for address in user.addresses:
        print(f"用户{user.name}的地址：{address.email_address}")

# 采用延迟加载的方式，这个其实是默认的方式
user = session.query(User).first()
# 只有在你访问addresses属性的时候才会去加载关联的addresses数据
addresses = user.addresses
for address in user.addresses:
    print(address.email_address)
